
import 'dart:convert';
import 'dart:ffi' as f;
import 'dart:io';

import 'package:flutter/foundation.dart';

// libSignature.so 文件是由 https://gitee.com/jacky_tool/cpp-signature 生成
class Signature {

  ///校验当前app是否是官方应用，没有被篡改
  ///
  ///该检测只适用于android版本， ios默认通过
  ///
  ///[androidPackage] 安卓app的包名
  ///
  ///[signatureInfo] 签名文件的md5信息含冒号
  ///
  ///[onlySign] 只检测签名信息，不检测包名
  static bool checkSignature(String androidPackage, String signatureInfo, [bool onlySign = false]) {
    if(!Platform.isAndroid) return true;

    String? greeting = _getSignature();
    if(greeting == null) return false;

    if (onlySign) {
      if (signatureInfo.length == 47) { //md5字符串的长度是47个字符
        return greeting.endsWith(signatureInfo);
      }
    } else {
      String s = "$androidPackage$signatureInfo";
      if (kDebugMode) print("Input Signature: $s");
      if (greeting.compareTo(s) == 0) return true;
    }
    return false;
  }

  ///多组包名和签名文件比对, 包名为key，签名为value
  ///返回匹配到的索引值，返回-1 表示没匹配
  static int checkMultiSignature(List<MapEntry<String, String>> signatures) {
    if(!Platform.isAndroid) return 0;
    if(signatures.isEmpty) return -1;

    String? greeting = _getSignature();
    if(greeting == null) return -1;

    int i = 0;
    for (var e in signatures) {
      String s = "${e.key}${e.value}";
      if (kDebugMode) print("Input Signature: $s");
      if (greeting.compareTo(s) == 0) return i;
      i++;
    }
    return -1;
  }

  static String? _getSignature() {
    try {
      final f.DynamicLibrary nativeLib = f.DynamicLibrary.open('libSignature.so');
      final signFunc = nativeLib.lookupFunction<f.Pointer<f.Int8> Function(),
          f.Pointer<f.Int8> Function()>('signature');
      f.Pointer<f.Int8> res = signFunc();
      String greeting = _toDartString(res); // res.cast<Uint8>().toDartString();
      assert(greeting != '', 'U must use ‘Signature.init(this)’ in Android Code');
      if (kDebugMode) print("Read Signature: $greeting");
      return greeting;
    } catch(e) {
      if(kDebugMode) print("Signature Error: $e");
    }
    return null;
  }

  static String _toDartString(f.Pointer<f.Int8> code) {
    final codeUnits = code.cast<f.Uint8>();
      int length = _length(codeUnits);
    return utf8.decode(codeUnits.asTypedList(length));
  }

  static int _length(f.Pointer<f.Uint8> codeUnits) {
    var length = 0;
    while (codeUnits[length] != 0) {
      length++;
    }
    return length;
  }

}
